//ENCRIPTION.v - This is the encription hardware for project 2.
//
// Created By:	Jesse Inkpen
// Date:	18-February-2014
//
// This module has a three fixed values applied to its input port and waits
// untill a go signal to start calculating an RSA encription block
// Use the define 'BITS to set the bit size of the ENCRIPTION.v synthesis.
///////////////////////////////////////////////////////////////////////////

`define BITS 16

module RSA(
	input						clk,		// clock
	input						go,		// hardware go go go
	input	[`BITS-1:0]		m,		// message
	input	[`BITS-1:0]		e,		// exponent
	input	[`BITS-1:0]		n,		// modulous
			
	output	reg [`BITS-1:0]		r,		// post processing result
	output	reg			d		// done signal
	);
	
	//****** Parameters ****************
	parameter	INIT			=	7'b0000001,
					CHECK_e		=	7'b0000010,
					CALC_P		=	7'b0000100,
					EVAL_Z		=	7'b0001000,
					UPD_P			=	7'b0010000,
					R_SHFT_EXP	=	7'b0100000,
					DONE			=	7'b1000000;
					
	reg [6:0]	State, NextState;

	reg 	[`BITS*2-1:0]	z;	// message register
	reg	[`BITS-1:0]		i;			// index
	reg	[`BITS*2-1:0]  p_old;
	reg	[`BITS*2-1:0]  p_new;
	reg	[`BITS-1:0]		exp;		//copy of exp used in modular exponentiation

	//Update state
	always @(posedge clk)
	begin
		if(go	== 0)
			State	<=	INIT;
		else
			State	<=	NextState;
	end	
		
	//Next state logic
	always @(State)
	begin
		case (State)
			INIT:			begin
								NextState	<=	CHECK_e;		
							end		
			CHECK_e:		begin
								if(exp != 0)	
									NextState <= CALC_P;
								else
									NextState <= DONE;
							end			
			CALC_P:		begin
								NextState <= EVAL_Z;		
							end
			EVAL_Z:		begin
								NextState <= UPD_P;			
							end
			UPD_P:		begin
								NextState <= R_SHFT_EXP;
							end
			R_SHFT_EXP:	begin
								NextState <= CHECK_e;
							end
			DONE:			begin
								NextState <= DONE;
							end
			default:		begin
								NextState <= INIT;
							end			
		endcase
	end
		
	//Output logic
	always @(State)
	begin
		case (State)
			INIT:			begin
								z		<=	1;
								p_old	<=	m;
								exp	<=	e;
							end
			CHECK_e:		begin
								exp	<=	exp;
							end			
			CALC_P:		begin
								p_new	<=	((p_old * p_old) % n);	
							end
			EVAL_Z:		begin
								if(exp[0] == 1)
								z <= ((z * p_old) % n);
							end
			UPD_P:		begin
								p_old	<= p_new;
							end
			R_SHFT_EXP:	begin
								exp <= exp >> 1;
							end
			DONE:			begin
								d <= 1;					// yes, flag done set
								r <= z[`BITS-1:0];	// output result
							end
			default:		begin
								d <= 0;					// yes, flag done set								
							end	
		endcase
	end
	
endmodule
		
		